use std::{
    fmt::Debug,
    mem::swap,
    sync::{Arc, Mutex},
};

use anyhow::Error;
use log::error;
use serde::Serialize;
use serde_json::Value;

use crate::{add, Message, MessageRole};

pub trait HistoryBatchEncodedType: Sized + Debug + Clone {
    fn new() -> Self;
    fn clear(&mut self) -> anyhow::Result<()>;
    fn len(&self) -> usize;
}

impl HistoryBatchEncodedType for String {
    fn new() -> Self {
        String::new()
    }
    fn clear(&mut self) -> anyhow::Result<()> {
        self.clear();
        Ok(())
    }
    fn len(&self) -> usize {
        self.len()
    }
}
pub trait HistoryEncoder: Debug + Clone {
    type BatchEncodedType: HistoryBatchEncodedType;
    type MessageRole: MessageRole;
    fn history_prefix_encode_batch(
        batch: &Self::BatchEncodedType,
        messages: &Vec<Message<Self::MessageRole>>,
    ) -> Self::BatchEncodedType;
    fn history_push_encode_batch(
        batch: &mut Self::BatchEncodedType,
        messages: &Vec<Message<Self::MessageRole>>,
    ) -> anyhow::Result<()> {
        let new_batch = Self::history_prefix_encode_batch(batch, messages);
        *batch = new_batch;
        Ok(())
    }
    fn history_push_encode_single(
        batch: &mut Self::BatchEncodedType,
        message: Message<Self::MessageRole>,
    ) -> anyhow::Result<()> {
        Self::history_push_encode_batch(batch, &vec![message])?;
        Ok(())
    }
}

#[derive(Debug, Clone)]
pub struct History<H>
where
    H: HistoryEncoder,
{
    coded: Arc<Mutex<H::BatchEncodedType>>,
    prefix: Vec<Message<H::MessageRole>>,
}

// impl Serialize for History {
//     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
//     where
//         S: serde::Serializer,
//     {
//         let coded = self
//             .coded
//             .try_lock()
//             .map_err(|e| {
//                 error!("Failed to lock coded history. Error : {}", e);
//                 Error::msg("Failed to lock coded history.")
//             })
//             .unwrap();
//         coded.serialize(serializer)
//     }
// }

impl<H> History<H>
where
    H: HistoryEncoder,
{
    pub fn new() -> Self {
        Self {
            coded: Arc::new(Mutex::new(H::BatchEncodedType::new())),
            prefix: vec![],
        }
    }
    pub fn clear(&mut self) -> anyhow::Result<()> {
        self.clear_prefix();
        let mut coded = self.coded.try_lock().map_err(|e| {
            error!("Failed to lock coded history. Error : {}", e);
            Error::msg("Failed to lock coded history.")
        })?;
        H::BatchEncodedType::clear(&mut coded)?;
        Ok(())
    }
    pub fn clear_prefix(&mut self) {
        self.prefix.clear()
    }
    pub fn push(&mut self, message: Message<H::MessageRole>) {
        self.prefix.push(message)
    }
    pub fn push_merge(&self, message: Message<H::MessageRole>) -> anyhow::Result<()> {
        let mut coded = self.coded.try_lock().map_err(|e| {
            error!("Failed to lock coded history. Error : {}", e);
            Error::msg("Failed to lock coded history.")
        })?;
        H::history_push_encode_single(&mut coded, message)?;
        Ok(())
    }
    pub fn merge(&mut self) -> anyhow::Result<()> {
        let mut coded = self.coded.try_lock().map_err(|e| {
            error!("Failed to lock coded history. Error : {}", e);
            Error::msg("Failed to lock coded history.")
        })?;
        let mut prefix = Vec::<Message<H::MessageRole>>::new();
        swap(&mut self.prefix, &mut prefix);
        H::history_push_encode_batch(&mut coded, &prefix)?;
        Ok(())
    }
    pub fn merge_history(&mut self, history: &mut History<H>) -> anyhow::Result<()> {
        let mut coded = self.coded.try_lock().map_err(|e| {
            error!("Failed to lock coded history.");
            Error::msg("Failed to lock coded history.")
        })?;
        H::history_push_encode_batch(&mut coded, &history.prefix)?;
        Ok(())
    }
    pub fn get_histry(&self, enable_prefix: bool) -> H::BatchEncodedType {
        let coded = self.coded.try_lock().unwrap().clone();
        if enable_prefix {
            H::history_prefix_encode_batch(&coded, &self.prefix)
        } else {
            H::history_prefix_encode_batch(&coded, &vec![])
        }
    }
}
